<template>
  <div
    ref="dragDropRef" ondragstart="return false"
    @mousedown="mousedown"
    @mouseout="mouseout"
    @mouseover="mouseover"
  >
    <div
      ref="dragDropContentRef" class="drag-drop-content"
      :style="{ transform: `translate(${translate.x}px,${translate.y}px) scale(${_scale})` }"
    >
      <slot name="default" :event="{ mouseup }" />
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, withDefaults } from 'vue'

const props = withDefaults(defineProps<{
  step?: number,
  scale?: boolean
}>(), {
  step: 0.1,
  scale: true
})

// region TODO 偏移信息
// 记录按下时的坐标点
let downPoint: any = null
// 记录按下时的偏移
let downRefPoint: any = null
// 偏移
const translate = ref({
  x: 0,
  y: 0
})
// 缩放
const _scale = ref(1)
// endregion

// region TODO 移动
const mousedown = (e: any) => {
  downPoint = {
    x: e.x,
    y: e.y
  }
  downRefPoint = JSON.parse(JSON.stringify(translate.value))
  document.addEventListener('mousemove', mousemove, this)
  document.addEventListener('mouseup', mouseup, this)
}
const mousemove = (e: any) => {
  const offsetPoint = {
    x: e.x - downPoint.x,
    y: e.y - downPoint.y
  }
  translate.value.x = downRefPoint.x + offsetPoint.x
  translate.value.y = downRefPoint.y + offsetPoint.y
}
const mouseup = () => {
  document.removeEventListener('mousemove', mousemove)
  document.removeEventListener('mouseup', mouseup)
}
// endregion

// region TODO 缩放
const mouseover = () => {
  if (props.scale) {
    document.addEventListener('mousewheel', mousewheel, { passive: false })
  }
}
const mouseout = () => {
  document.removeEventListener('mousewheel', mousewheel)
}
// endregion

// region TODO 鼠标滚动
const mousewheel = (e: any) => {
  e.preventDefault()
  if (e.deltaY > 0) {
    if (_scale.value - props.step >= 0) {
      _scale.value = _scale.value - props.step
    }
  } else {
    _scale.value = _scale.value + props.step
  }
}
// endregion

// region TODO 恢复默认大小
const reset = () => {
  translate.value.x = 0
  translate.value.y = 0
  _scale.value = 1
}
// endregion

// region TODO 自适应大小
const dragDropRef = ref<HTMLElement>()
const dragDropContentRef = ref<HTMLElement>()
const autoSize = () => {
  if (dragDropRef.value && dragDropContentRef.value) {
    const width = dragDropRef.value?.offsetWidth
    const height = dragDropRef.value?.offsetHeight
    const cWidth = dragDropContentRef.value?.offsetWidth
    const cHeight = dragDropContentRef.value?.offsetHeight
    const hScale = height / cHeight
    const wScale = width / cWidth
    if (hScale * cWidth <= width) {
      _scale.value = hScale
    } else {
      _scale.value = wScale
    }
    translate.value.y = -((cHeight - (cHeight * hScale))) / 2
    translate.value.x = -((cWidth - (cWidth * wScale))) / 2
  }
}
// endregion

function getOption () {
  return {
    translate: translate.value,
    scale: _scale.value
  }
}

function setOption (option: { translate, scale }) {
  translate.value = option.translate
  _scale.value = option.scale
}

defineExpose({
  reset,
  autoSize,
  getOption,
  setOption
})
</script>

<style lang="scss" scoped>
.drag-drop-content {
  width: fit-content;
  height: fit-content;
}
</style>
